<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>装饰器设计模式</title>
</head>
<body>
<script>
    /*
    * 装饰器设计模式的本质就是在我们运行函数的时候进行一些小操作，比如延时执行啊,根据一定的条件来控制我们的函数执行啊
    * 他并不会修改函数的逻辑，只是在控制原函数的执行
    * */

    function foo(x) {
        console.log("执行了")
        return x
    }


    function decor(f) {
        let map = new Map()
        return function (a) {
            if (map.has(a)) {
                return map.get(a)
            }
            let res = f(a)
            map.set(a, res)
            return res
        }
    }

    function de(f, a) {
        let map = new Map()
        return function () {
            if (map.has(a)) {
                return map.get(a)
            }
            let res = f(a)
            map.set(a, res)
            return res
        }
    }

    // foo =  decor(foo)
    //    console.log(foo(1213));
    //    console.log(foo(1213));


    // foo = de(foo,1)
    // console.log(foo());
    // console.log(foo());


    // function foo1(a,b,c){
    //
    // }


    let obj = {
        age: 12,
        tell(a, b, c) {
            console.log(a, b, c)
            console.log("函数执行了")
            return this.age
        }
    }

    function hash() {
        return Array.prototype.join(arguments)
    }

    function wrapper(fn) {
        let map = new Map()
        return function () {
            let key = hash(arguments)
            if (map.has(key)) {
                return map.get(key)
            }
            let res = fn.apply(this, arguments)
            map.set(key, res)
            return res
        }
    }

    //
    // obj.tell =   wrapper(obj.tell)
    //    console.log(obj.tell(1, 2, 3));
    //    console.log(obj.tell(1, 2, 3));
    //    console.log(obj.tell(1, 2, 3));
    //    console.log(obj.tell(1, 2, 3));


    let user = {
        age: 12,
        speak() {
            console.log(this.age)
            // forward(1,2,3)

            forward.apply(this, [1, 2, 3])
        }
    }

    //呼叫转移
    function forward() {
        //因为在user对象调用forward的时候直接调用那么此处的this就是window
        console.log(arguments)
        console.log(this)
        //    如果我们要在user中沿用user内的this的话要使用呼叫转移技术
        //    呼叫转移的本质其实是this的传递 在调用函数的时候我们不仅会被传递函数参数 也是在传递this 只不过很多时候我们不会这样去操作
        //    因为我们调用对象函数的时候都是使用【对象.方法名()】进行调用 很少会将对象的方法传递给另外一个变量去调用
        /*
        * 在对象方法中调用外部的函数，如果想让外部的函数可以沿用对象的this那么我们 不能直接调用外部的函数，因为这样操作的话this会变成window
        * 我们可以使用bind/call/apply修改当前的调用者
        *
        * 一般使用呼叫转移的地方一个是对象.函数()这种调用方式的函数中，另一种是class的构方法中，因为在这两种环境下this是当前的对象
        *
        *
        * */
    }

    user.speak()


</script>
</body>
</html>